home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 January / macpower199701.bin / AMUG / Programming_10 / WASTE 1.3a1.sit / WASTE 1.3a1 Distribution / WASTE 1.3a1 / WEScraps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-23  |  11.2 KB  |  437 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    WEScraps.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  Routines for Manipulating Style Scraps and Object Soups
  6.  *
  7.  *  Copyright (c) 1993-1996 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. pascal OSErr _WEPrependStyle(Handle hStyleScrap, const WERunInfo *info, SInt32 offsetDelta)
  18. {
  19.     // compare the stylistic attributes in info with the first element of the specified
  20.     // style scrap: if they differ, prepend a new element to the style scrap.
  21.     // in any case, advance all character offsets in the style scrap by offsetDelta
  22.  
  23.     TEStyleScrapPtr pScrap;
  24.     TEStyleScrapElement element;
  25.     SInt16 i;
  26.     OSErr err;
  27.  
  28.     pScrap = * (TEStyleScrapHandle) hStyleScrap;
  29.  
  30.     // compare this style info with that stored in the first element of our private style scrap
  31.     if (!_WEBlockCmp(&pScrap->scrpStyleTab[0].scrpTEAttrs, &info->runAttrs, sizeof(TERunAttributes)))
  32.     {
  33.         // insert a new style scrap element at the beginning of the style scrap
  34.         element.scrpStartChar = 0;
  35.         element.scrpTEAttrs = * (TERunAttributes *) &info->runAttrs;
  36.  
  37.         if ((err = _WESplice(hStyleScrap, &element, sizeof(element), sizeof(SInt16))) != noErr)
  38.             return err;
  39.  
  40.         pScrap = * (TEStyleScrapHandle) hStyleScrap;
  41.  
  42.         // increment element count
  43.         pScrap->scrpNStyles++;
  44.  
  45.     } // if not _WEBlockCmp
  46.  
  47.     // update char offsets within the style scrap
  48.     for ( i = pScrap->scrpNStyles - 1; i > 0; i-- )
  49.         pScrap->scrpStyleTab[i].scrpStartChar += offsetDelta;
  50.  
  51.     return noErr;
  52.  
  53. }
  54.  
  55. pascal OSErr _WEAppendStyle(Handle hStyleScrap, const WERunInfo *info, SInt32 offset)
  56. {
  57.  
  58.     // compare the stylistic attributes in info with the last element of the specified
  59.     // style scrap: if they differ, append a new element to the style scrap.
  60.  
  61.     TEStyleScrapPtr pScrap;
  62.     TEStyleScrapElement element;
  63.     OSErr err;
  64.  
  65.     pScrap = * (TEStyleScrapHandle) hStyleScrap;
  66.     // compare this style info with that stored in the first element of our private style scrap
  67.     if (!_WEBlockCmp(&pScrap->scrpStyleTab[pScrap->scrpNStyles - 1].scrpTEAttrs,
  68.         &info->runAttrs, sizeof(TERunAttributes)))
  69.     {
  70.  
  71.         // create a new style scrap element
  72.         element.scrpStartChar = offset;
  73.         element.scrpTEAttrs = * (TERunAttributes *) &info->runAttrs;
  74.  
  75.         // append it at the end of the style scrap
  76.         if ((err = _WESplice(hStyleScrap, &element, sizeof(element), -1)) != noErr)
  77.             return err;
  78.  
  79.         // increment scrap counter
  80.         pScrap = * (TEStyleScrapHandle) hStyleScrap;
  81.         pScrap->scrpNStyles++;
  82.  
  83.     } // if not _WEBlockCmp
  84.  
  85.     // return result code
  86.     return noErr;
  87. }
  88.  
  89. #if WASTE_OBJECTS
  90.  
  91. pascal OSErr _WEPrependObject(Handle hSoup, const WERunInfo *info, SInt32 offsetDelta)
  92. {
  93.     // if info describes an embedded object, prepend a new object descriptor,
  94.     // complete with the associated object data, to the specified soup.
  95.     // in any case, advance all character offsets in the soup by offsetDelta
  96.  
  97.     WEObjectDescHandle hObjectDesc = info->runAttrs.runStyle.tsObject;
  98.     Handle hObjectData = nil;
  99.     FlavorType objectType;
  100.     Boolean disposeData;
  101.     Ptr pSoup;
  102.     WESoup soup;
  103.     Size soupSize, objectDataSize, extraSize;
  104.     OSErr err;
  105.  
  106.     // get size of existing soup
  107.     soupSize = GetHandleSize(hSoup);
  108.  
  109.     if (hObjectDesc != nil)
  110.     {
  111.         // create a temporary handle for the streaming callback
  112.         if ((err = _WEAllocate(0, kAllocTemp, &hObjectData)) != noErr)
  113.             goto cleanup;
  114.  
  115.         // get the object type/data
  116.         if ((err = _WEStreamObject(weToSoup, &objectType, &hObjectData, &disposeData, hObjectDesc)) != noErr)
  117.             goto cleanup;
  118.  
  119.         // get size of object data
  120.         objectDataSize = GetHandleSize(hObjectData);
  121.  
  122.         // extraSize is size of descriptor + size of object data
  123.         extraSize = sizeof(soup) + objectDataSize;
  124.  
  125.         // fill in a soup item
  126.         BLOCK_CLR(soup);
  127.         soup.soupType = objectType;
  128.         soup.soupSize = (*hObjectDesc)->objectSize;
  129.         soup.soupDataSize = objectDataSize;
  130.  
  131.         // make room for the descriptor and the object data
  132.         if ((err = _WESplice(hSoup, nil, extraSize, 0)) != noErr)
  133.             goto cleanup;
  134.  
  135.         // insert the new object descriptor at the beginning
  136.         pSoup = *hSoup;
  137.         BlockMoveData(&soup, pSoup, sizeof(soup));
  138.  
  139.         // copy the object data
  140.         BlockMoveData(*hObjectData, pSoup + sizeof(soup), objectDataSize);
  141.     }
  142.     else
  143.     {
  144.         pSoup = *hSoup;
  145.         extraSize = 0;
  146.     }
  147.  
  148.     // update char offsets within the soup
  149.     while (soupSize > 0)
  150.     {
  151.         pSoup += extraSize;
  152.  
  153.         //    we have to use BlockMoveData to access descriptors within
  154.         //    the soup, as they might be odd-aligned (duh!) and that would
  155.         //    cause fatal address errors on 68000 CPUs
  156.  
  157.         BlockMoveData(pSoup, &soup, sizeof(soup));
  158.         soup.soupOffset += offsetDelta;
  159.         BlockMoveData(&soup, pSoup, sizeof(soup));
  160.         extraSize = sizeof(soup) + soup.soupDataSize;
  161.         soupSize -= extraSize;
  162.     }
  163.  
  164.     err = noErr;
  165.  
  166. cleanup:
  167.     if (disposeData)
  168.         _WEForgetHandle(&hObjectData);
  169.  
  170.     return err;
  171.  
  172. }
  173.  
  174. pascal OSErr _WEAppendObject(Handle hSoup, const WERunInfo *info, SInt32 offset)
  175. {
  176.  
  177.     // if info describes an embedded object, append a new object descriptor,
  178.     // complete with the associated object data, to the specified soup.
  179.  
  180.     WEObjectDescHandle hObjectDesc = info->runAttrs.runStyle.tsObject;
  181.     Handle hObjectData = nil;
  182.     FlavorType objectType;
  183.     WESoup soup;
  184.     Boolean saveDataLock;
  185.     Boolean disposeData;
  186.     OSErr err;
  187.  
  188.     if (hObjectDesc != nil)
  189.     {
  190.         // create a temporary handle for the streaming callback
  191.         if ((err = _WEAllocate(0, kAllocTemp, &hObjectData)) != noErr)
  192.             goto cleanup;
  193.  
  194.         // get the object type/data
  195.         if ((err = _WEStreamObject(weToSoup, &objectType, &hObjectData, &disposeData, hObjectDesc)) != noErr)
  196.             goto cleanup;
  197.  
  198.         // fill in a soup item
  199.         BLOCK_CLR(soup);
  200.         soup.soupOffset = offset;
  201.         soup.soupType = objectType;
  202.         soup.soupSize = (*hObjectDesc)->objectSize;
  203.         soup.soupDataSize = GetHandleSize(hObjectData);
  204.  
  205.         // append it to the soup handle
  206.         if ((err = _WESplice(hSoup, &soup, sizeof(soup), -1)) != noErr)
  207.             goto cleanup;
  208.  
  209.         // append the actual object data to the soup handle
  210.         saveDataLock = _WESetHandleLock(hObjectData, true);
  211.         err = _WESplice(hSoup, *hObjectData, soup.soupDataSize, -1);
  212.         _WESetHandleLock(hObjectData, saveDataLock);
  213.         if (err != noErr)
  214.             goto cleanup;
  215.     } // if object reference is not nil
  216.  
  217.     err = noErr;
  218.  
  219. cleanup:
  220.     if (disposeData)
  221.         _WEForgetHandle(&hObjectData);
  222.  
  223.     return err;
  224.  
  225. }
  226.  
  227. #endif
  228.  
  229. pascal OSErr WECopyRange(SInt32 rangeStart, SInt32 rangeEnd, Handle hText,
  230.                     Handle hStyles, Handle hSoup, WEHandle hWE)
  231. {
  232.  
  233.     // Make a copy of the specified range of text: store the characters in hText
  234.     // and the associated style scrap in hStyles.  The handles are resized as necessary.
  235.     // Specify nil in hText or hStyles if you don't want the corresponding info returned.
  236.  
  237.     WEPtr pWE;
  238.     TEStyleScrapElementPtr pElement;
  239.     SInt32 rangeLength;
  240.     SInt32 firstRun, nRuns, i;
  241.     SInt32 startChar;
  242.     WERunInfo info;
  243.     Boolean saveWELock;
  244.     OSErr err;
  245.  
  246.     // lock the WE record
  247.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  248.     pWE = *hWE;
  249.  
  250.     // range-check parameters and reorder them if necessary
  251.     rangeStart = _WEPinInRange(rangeStart, 0, pWE->textLength);
  252.     rangeEnd = _WEPinInRange(rangeEnd, 0, pWE->textLength);
  253.     _WEReorder(&rangeStart, &rangeEnd);
  254.     rangeLength = rangeEnd - rangeStart;
  255.  
  256.     if (hText != nil)
  257.     {
  258.         // resize the given handle
  259.         SetHandleSize(hText, rangeLength);
  260.         if ((err = MemError()) != noErr)
  261.             goto cleanup;
  262.  
  263.         // copy the text range
  264.         BlockMoveData(*pWE->hText + rangeStart, *hText, rangeLength);
  265.     }
  266.  
  267.     // make the soup handle zero-length
  268.     if (hSoup != nil)
  269.     {
  270.         SetHandleSize(hSoup, 0);
  271.         if ((err = MemError()) != noErr)
  272.             goto cleanup;
  273.     }
  274.  
  275.     if ((hStyles != nil) || (hSoup != nil))
  276.     {
  277.         // count how many style runs there are in the selection range
  278.         firstRun = WEOffsetToRun(rangeStart, hWE);
  279.         nRuns = WEOffsetToRun(rangeEnd - 1, hWE) - firstRun + 1;
  280.  
  281.         if (hStyles != nil)
  282.         {
  283.             // resize the given style scrap handle and lock it in high heap
  284.             SetHandleSize(hStyles, (nRuns * sizeof(ScrpSTElement)) + sizeof(SInt16));
  285.             if ((err = MemError()) != noErr)
  286.                 goto cleanup;
  287.             HLockHi(hStyles);
  288.  
  289.             // fill in the style count in the style scrap
  290.             // *** POTENTIAL PROBLEM: if nRuns > 32767, scrpNStyles will be invalid ***
  291.             WEASSERT(nRuns <= SHRT_MAX, "¥pToo many styles");
  292.             (* (TEStyleScrapHandle) hStyles)->scrpNStyles = nRuns;
  293.         }
  294.  
  295.         pElement = & ((* (TEStyleScrapHandle) hStyles)->scrpStyleTab[0]);
  296.         // loop through every style run in the selection range
  297.         for ( i = 0; i < nRuns; i++ )
  298.         {
  299.             _WEGetIndStyle(firstRun + i, &info, hWE);
  300.  
  301.             // calculate the start character for this style run, relative to the beginning of the range
  302.             startChar = info.runStart - rangeStart;
  303.             if (startChar < 0)
  304.             {
  305.                 startChar = 0;
  306. #if WASTE_OBJECTS
  307.                 info.runAttrs.runStyle.tsObject = nil;
  308. #endif
  309.             }
  310.             if (hStyles != nil)
  311.             {
  312.                 info.runAttrs.runStyle.tsFlags = 0; // don't export internal flags
  313.                 pElement->scrpStartChar = startChar;
  314.                 pElement->scrpTEAttrs = * (TERunAttributes *) &info.runAttrs;
  315.                 pElement++;
  316.             }
  317.  
  318. #if WASTE_OBJECTS
  319.             if (hSoup != nil)
  320.             {
  321.                 // if this style run references an embedded object, append it to the "soup"
  322.                 if (info.runAttrs.runStyle.tsObject != nil)
  323.                 {
  324.                     if ((err = _WEAppendObject(hSoup, &info, startChar)) != noErr)
  325.                         goto cleanup;
  326.                 }
  327.             }
  328. #endif
  329.  
  330.         }
  331.     }
  332.     // clear result code
  333.     err = noErr;
  334.  
  335. cleanup:
  336.  
  337.     // unlock the style scrap handle
  338.     if (hStyles != nil)
  339.         HUnlock(hStyles);
  340.  
  341.     // unlock the WE record
  342.     _WESetHandleLock((Handle) hWE, saveWELock);
  343.     // return result code
  344.     return err;
  345. }
  346.  
  347. pascal OSErr WECopy(WEHandle hWE)
  348. {
  349.     // Copy the selection range to the desk scrap
  350.  
  351.     WEPtr pWE;
  352.     AEDesc d[3] = { { kTypeText, nil }, { kTypeStyles, nil }, { kTypeSoup, nil } };
  353.     Handle hItem;
  354.     Size itemSize;
  355.     SInt16 i, numTypes;
  356.     Boolean saveWELock;
  357.     Boolean saveDataLock;
  358.     Boolean disposeData = true;
  359.     OSErr err;
  360. #if WASTE_OBJECTS
  361.     WEObjectDescHandle hObjectDesc = nil;
  362. #endif
  363.  
  364.     // lock the WE record
  365.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  366.     pWE = *hWE;
  367.  
  368.     // return weEmptySelectionErr if the selection range is empty
  369.     if (pWE->selStart == pWE->selEnd)
  370.     {
  371.         err = weEmptySelectionErr;
  372.         goto cleanup;
  373.     }
  374.  
  375.     // clear the desk scrap
  376.     if ((err = ZeroScrap()) != noErr)
  377.         goto cleanup;
  378.  
  379. #if WASTE_OBJECTS
  380.     numTypes = (BTST(pWE->features, weFMonoStyled) || (WEGetSelectedObject(&hObjectDesc, hWE) == noErr)) ? 1 : 3;
  381. #else
  382.     numTypes = BTST(pWE->features, weFMonoStyled) ? 1 : 2;
  383. #endif
  384.  
  385.     // allocate some temporary handles
  386.     for ( i = 0; i < numTypes; i++ )
  387.     {
  388.         if ((err = _WEAllocate(0, kAllocTemp, &d[i].dataHandle)) != noErr)
  389.             goto cleanup;
  390.     }
  391.  
  392. #if WASTE_OBJECTS
  393.     if (hObjectDesc != nil)
  394.     {
  395.         if ((err = _WEStreamObject(weToScrap, &d[0].descriptorType, &d[0].dataHandle,
  396.                     &disposeData, hObjectDesc)) != noErr)
  397.             goto cleanup;
  398.     }
  399.     else
  400. #endif
  401.     {
  402.         // make a copy of the selection text and styles and create an object "soup"
  403.         if ((err = WECopyRange(pWE->selStart, pWE->selEnd,
  404.             d[0].dataHandle, d[1].dataHandle, d[2].dataHandle, hWE)) != noErr)
  405.             goto cleanup;
  406.     }
  407.  
  408.     // copy the items to the desk scrap
  409.     for ( i = 0; i < numTypes; i++ )
  410.     {
  411.         hItem = d[i].dataHandle;
  412.         itemSize = GetHandleSize(hItem);
  413.         if (itemSize > 0)
  414.         {
  415.             saveDataLock = _WESetHandleLock(hItem, true);
  416.             err = PutScrap(itemSize, d[i].descriptorType, *hItem);
  417.             _WESetHandleLock(hItem, saveDataLock);
  418.             if (err != noErr)
  419.                 goto cleanup;
  420.         }
  421.     }
  422.  
  423.     // clear result code
  424.     err = noErr;
  425.  
  426. cleanup:
  427.     // clean up
  428.     if (disposeData)
  429.     {
  430.         _WEForgetHandle(&d[0].dataHandle);
  431.         _WEForgetHandle(&d[1].dataHandle);
  432.         _WEForgetHandle(&d[2].dataHandle);
  433.     }
  434.     _WESetHandleLock((Handle) hWE, saveWELock);
  435.     return err;
  436. }
  437.